package vpc.ext.stacksize;


import java.io.IOException;
import java.io.PrintStream;

import vpc.core.Program;
import vpc.core.virgil.VirgilClass;
import vpc.core.virgil.VirgilComponent;
import vpc.core.decl.Method;
import vpc.core.ProgramDecl.EntryPoint;
import vpc.hil.*;
import vpc.sched.Stage;
import vpc.ext.stacksize.util.VstackException;
import vpc.ext.stacksize.visitors.*;
import vpc.ext.stacksize.util.Debug;
import vpc.ext.stacksize.util.DataHandler;
import vpc.ext.stacksize.util.VstackException;
import vpc.tir.TIRRep;
import vpc.tir.TIRUtil;
import vpc.tir.TIRPrinter;
import cck.text.Printer;
import java.util.*;


public class StackBoundStage extends Stage {

	private static void debugEntryPoints(PrintStream out, Program p) {
		out.println("DEBUG: Printing entrypoints");
		for (EntryPoint e : p.programDecl.entryPoints) {
			out.println("\tEntryPoint = " + e.getName());
		}
		return;
	}
	
	
	private GraphVisitor gv;

	public void visitProgram(Program program) throws IOException {
		try {
			Debug.init(System.out);
			InterruptMask.init(program.targetDevice);
		} catch (IOException e) {
			System.err
					.println("WARNING: could not load vstack debug properties.");
			e.printStackTrace();
		}

		gv = new GraphVisitor(program);
		
//		debugEntryPoints(System.out, program);
		
		for (Method m : program.closure.methods) {

			gv.setParentByName(m.getFullName());

			if (gv.context.parent == null) {
				gv.context.parent = new Node(m.getFullName(), DataHandler
						.getStackPush(m));
				gv.subRoots.add(gv.context.parent);
			}

			this.visitMethod(m);
		}

		if (Debug.Flag.PRINTGRAPH.isSet()) {
			Debug.println(Debug.seperator1, Debug.Flag.PRINTGRAPH);
			gv.context.root.printGraph(System.out, new HashSet<Node>());
		}

		try {
			System.out.println("maxStackPush() = "
					+ gv.context.root.getMaxPush(new HashSet<Node>()));
		} catch (VstackException.CycleException c) {
			System.out.println("Cycle detected!");
		}

		return;
	}

	public void visitMethod(Method m) {
		TIRRep r = TIRUtil.getRep(m);
		gv.visitBody(r.getBody());
		return;
	}

}
